<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="./node_modules/lodash/lodash.min.js"></script>
</head>

<body>
  <script>
    // const obj1 = { name: 'ifer', age: 18, address: { province: '河南', city: '周口' } };

    // 这叫引用之间的赋值，会相互影响
    /* const o = obj1;
    console.log(o); */

    /* const o = JSON.parse(JSON.stringify(obj1))
    // console.log(o);
    o.address.province = '湖北'
    console.log(obj1.address.province); // '河南' */


    // ..........JSON.stringify 的确点............

    // 1. 会忽略值为 undefined、函数、Symbol
    // 2. 当值为 bigint 或循环引用的时候会报错
    // 3. 日期会被转成字符串、正则会被转成空对象
    // 4. ...
    const obj1 = { name: 'ifer', age: 18, address: { province: '河南', city: '周口' }, un: undefined, fn: function () { }, sm: Symbol(), d: new Date(), reg: /\d/, bi: 100n };
    const obj2 = {}
    obj1.children = obj2;
    obj2.parent = obj1

    // 这就叫循环引用，a 用了 b，b 又用了 a
    /* const obj2 = {}
    obj1.children = obj2;
    obj2.parent = obj1; */

    /* const o = JSON.parse(JSON.stringify(obj1))
    console.log(o); */


    // ..........三个点和 Object.assign 都是浅拷贝............

    // 它们都是用来进行浅拷贝的，好的地方是能拷贝 undefined、函数、Symbol、正则...
    /* const o = { ...obj1 }
    // Object.assign(o, obj1)
    o.address.province = '湖北'
    console.log(obj1.address.province) */

    /* o.name = 'xxx'
    console.log(obj1.name); */


    // ...............自己实现深拷贝：递归浅拷贝..........................

    /* const r = /\d/
    const o1 = new r.constructor(r)
    console.log(o1) */

    /* const d = new Date()
    const d2 = new d.constructor(d)
    console.log(d2) */

    /* const e = new Error('xxx')
    console.log(e)
    const e2 = new e.constructor(e.message)
    console.log(e2) */

    /* function fn() {
      return 2
    }
    const fn2 = new Function('return ' + fn.toString())()
    console.log(fn2 === fn) */

    // const copy = (target) => {
    //   const type = Object.prototype.toString.call(target)
    //   // 正则、日期
    //   if (/(regexp|date)/i.test(type)) return new target.constructor(target)
    //   // 错误对象
    //   if (/error/i.test(type)) return new target.constructor(target.message)
    //   // 函数
    //   if (/function/i.test(type)) return new Function('return ' + target.toString())()
    //   // null 和 简单数据类型
    //   if (target === null || typeof target !== 'object') return target
    //   // 数组和对象
    //   /* const arr = []
    //   const obj = {} */
    //   const result = new target.constructor()
    //   for (const attr in target) {
    //     result[attr] = copy(target[attr])
    //   }
    //   return result
    // }

    // const o = copy(obj1);
    // // o.address.province = '湖北~~'
    // // console.log(obj1.address.province); //
    // console.log(o.fn === obj1.fn)

    // ............处理循环引用的情况.................
    // 可以把循环引用的这个对象，当做 key 进行存储，下次直接获取就行了

    // Map 数据结构有一个很明显的特点，key 可以是对象
    // #1 => m = new Map()
    // const copy = (target, m = new Map()) => {
    //   const type = Object.prototype.toString.call(target)
    //   // 正则、日期
    //   if (/(regexp|date)/i.test(type)) return new target.constructor(target)
    //   // 错误对象
    //   if (/error/i.test(type)) return new target.constructor(target.message)
    //   // 函数
    //   if (/function/i.test(type)) return new Function('return ' + target.toString())()
    //   // null 和 简单数据类型
    //   if (target === null || typeof target !== 'object') return target
    //   // 数组和对象
    //   /* const arr = []
    //   const obj = {} */
    //   // #2 m 里面存储了 target 就直接返回
    //   // console.log(target, 233)

    //   if (m.get(target)) return m.get(target)
    //   const result = new target.constructor()
    //   // #3
    //   m.set(target, result)

    //   for (const attr in target) {
    //     // #4 传递 m
    //     result[attr] = copy(target[attr], m)
    //   }
    //   return result
    // };
    // // console.log(obj1)
    // const o = copy(obj1);
    // console.log(o)

    // ............不过，一般工作中我会使用 lodash 提供的 cloneDeep 方法.................
    /* const o = _.cloneDeep(obj1)
    console.log(o.fn === obj1.fn) */

    const p = new Promise((resolve, reject) => {
      reject(new Error('233'))
    })
    p.catch((r) => {
      console.log(r)
      return Promise.resolve(undefined)
    }).then((r) => {
      console.log(r)
    })

  </script>
</body>

</html>